//
//  TestOpenAL.cpp
//  NanoOSX
//
//  Created by Jeppe Nielsen on 9/30/13.
//  Copyright (c) 2013 Jeppe Nielsen. All rights reserved.
//


//http://www.youtube.com/user/thecplusplusguy
//Playing 3D sound with OpenAL, and loading a wav file manually
#include <iostream>
#include <fstream>
#include <cstring>
#include <OpenAL/al.h>
#include <OpenAL/alc.h>


#include "Engine.hpp"
#include "FileReader.hpp"



class TestOpenAL : public GameState<TestOpenAL> {
    
    bool isBigEndian()
    {
        int a=1;
        return !((char*)&a)[0];
    }
    
    int convertToInt(char* buffer,int len)
    {
        int a=0;
        if(!isBigEndian())
            for(int i=0;i<len;i++)
                ((char*)&a)[i]=buffer[i];
        else
            for(int i=0;i<len;i++)
                ((char*)&a)[3-i]=buffer[i];
        return a;
    }
    
    char* loadWAV(const char* fn,int& chan,int& samplerate,int& bps,int& size)
    {
        char buffer[4];
        std::ifstream in(fn,std::ios::binary);
        in.read(buffer,4);
        if(strncmp(buffer,"RIFF",4)!=0)
        {
            std::cout << "this is not a valid WAVE file"  << std::endl;
            return NULL;
        }
        in.read(buffer,4);
        in.read(buffer,4);	//WAVE
        in.read(buffer,4);	//fmt
        in.read(buffer,4);	//16
        in.read(buffer,2);	//1
        in.read(buffer,2);
        chan=convertToInt(buffer,2);
        in.read(buffer,4);
        samplerate=convertToInt(buffer,4);
        in.read(buffer,4);
        in.read(buffer,2);
        in.read(buffer,2);
        bps=convertToInt(buffer,2);
        in.read(buffer,4);	//data
        in.read(buffer,4);
        size=convertToInt(buffer,4);
        char* data=new char[size];
        in.read(data,size);
        return data;
    }
    
    char* waveData;
    int channel,sampleRate,bps,size;
    
    ALCdevice* device;
    ALCcontext* context;
    
    unsigned int bufferid,format;
    
    unsigned int sourceid;
    
    void Initialized() {
        waveData = loadWAV(FileReader::GetFile("drumloop.wav").c_str(),channel,sampleRate,bps,size);
        
        ALCdevice* device=alcOpenDevice(NULL);
        if(device==NULL)
        {
            std::cout << "cannot open sound card" << std::endl;
            return;
        }
        ALCcontext* context=alcCreateContext(device,NULL);
        if(context==NULL)
        {
            std::cout << "cannot open context" << std::endl;
            return;
        }
        alcMakeContextCurrent(context);
        
       
        alGenBuffers(1,&bufferid);
        if(channel==1)
        {
            if(bps==8)
            {
                format=AL_FORMAT_MONO8;
            }else{
                format=AL_FORMAT_MONO16;
            }
        }else{
            if(bps==8)
            {
                format=AL_FORMAT_STEREO8;
            }else{
                format=AL_FORMAT_STEREO16;
            }
        }
        
        alBufferData(bufferid,format,waveData,size,sampleRate);
        
        alGenSources(1,&sourceid);
        alSourcei(sourceid,AL_BUFFER,bufferid);
        
        alSourcePlayv(1, &sourceid);
    }
    
    void Destroyed() {
        alDeleteSources(1,&sourceid);
        alDeleteBuffers(1,&bufferid);
        
        alcDestroyContext(context);
        alcCloseDevice(device);
        delete[] waveData;
    }
    
    void Update(float dt) {
        
        alSource3f(sourceid,AL_POSITION,0,0,0);
		alSourcei(sourceid,AL_LOOPING,AL_TRUE);
		
		float f[]={1,0,0,0,1,0};
		alListenerfv(AL_ORIENTATION,f);
    }
    
    
};

/*

int main() {
   
    Engine e;
    e.Start<TestOpenAL>();
    
    return 0;
}
 */

/*
int main(int argc,char** argv)
{
	int channel,sampleRate,bps,size;
	char* data=loadWAV("test.wav",channel,sampleRate,bps,size);
	ALCdevice* device=alcOpenDevice(NULL);
	if(device==NULL)
	{
		std::cout << "cannot open sound card" << std::endl;
		return 0;
	}
	ALCcontext* context=alcCreateContext(device,NULL);
	if(context==NULL)
	{
		std::cout << "cannot open context" << std::endl;
		return 0;
	}
	alcMakeContextCurrent(context);
	
	unsigned int bufferid,format;
	alGenBuffers(1,&bufferid);
	if(channel==1)
	{
		if(bps==8)
		{
			format=AL_FORMAT_MONO8;
		}else{
			format=AL_FORMAT_MONO16;
		}
	}else{
		if(bps==8)
		{
			format=AL_FORMAT_STEREO8;
		}else{
			format=AL_FORMAT_STEREO16;
		}
	}
	alBufferData(bufferid,format,data,size,sampleRate);
	unsigned int sourceid;
	alGenSources(1,&sourceid);
	alSourcei(sourceid,AL_BUFFER,bufferid);
	
	Uint32 start;
	bool running;
	bool b[4]={0,0,0,0};
	float x=0,z=0;
	while(running)
	{
		start=SDL_GetTicks();
		while(SDL_PollEvent(&event))
		{
			switch(event.type)
			{
				case SDL_QUIT:
					running=false;
					break;
				case SDL_KEYDOWN:
					switch(event.key.keysym.sym)
                {
                    case SDLK_UP:
                        b[0]=true;
                        break;
                    case SDLK_RIGHT:
                        b[1]=true;
                        break;
                    case SDLK_DOWN:
                        b[2]=true;
                        break;
                    case SDLK_LEFT:
                        b[3]=true;
                        break;
                    case SDLK_SPACE:
                        alSourcePlay(sourceid);
                        break;
                }
					break;
				case SDL_KEYUP:
					switch(event.key.keysym.sym)
                {
                    case SDLK_UP:
                        b[0]=false;
                        break;
                    case SDLK_RIGHT:
                        b[1]=false;
                        break;
                    case SDLK_DOWN:
                        b[2]=false;
                        break;
                    case SDLK_LEFT:
                        b[3]=false;
                        break;
                }
					break;
			}
		}
		
		if(b[0])
			z+=0.3;
		if(b[1])
			x+=0.3;
		if(b[2])
			z-=0.3;
		if(b[3])
			x-=0.3;
		alSource3f(sourceid,AL_POSITION,0,0,0);
		alSourcei(sourceid,AL_LOOPING,AL_TRUE);
		
		
		float f[]={1,0,0,0,1,0};
		alListenerfv(AL_ORIENTATION,f);
		
        
	}
	
	alDeleteSources(1,&sourceid);
	alDeleteBuffers(1,&bufferid);
	
	alcDestroyContext(context);
	alcCloseDevice(device);
	delete[] data;
	return 0;
}

*/